package com.lovo.redis.service;

import com.lovo.redis.dao.ITicketDao;
import com.lovo.redis.util.CacheUtil;
import com.lovo.redis.util.SysBloomFilter;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;

import java.util.concurrent.TimeUnit;
@Service
public class TicketService implements ITicketService{
  @Autowired
  private RedisTemplate<String,Object> redisTemplate;
  @Autowired
  private ITicketDao ticketDao;
    @Autowired
    private RLock rLock;

    public Object findTicket(String movieName, float price) throws InterruptedException {
            //过滤条件防止缓存穿透
            if(!SysBloomFilter.bloomFilter.mightContain(movieName)||
                    !SysBloomFilter.bloomFilter.mightContain(String.valueOf(price))){
                return  null;
            }

            //先判断缓存中是否存在？读取缓存:去数据库查询，放入缓存。
            String key=movieName+"_"+price;
            Object list;
            if(redisTemplate.hasKey(key)){
                //有
                list=redisTemplate.opsForValue().get(key);
            }else {
                //没有，去竞争锁
           boolean lockBl=     rLock.tryLock(0,10,TimeUnit.SECONDS);
               if(lockBl) {
                   list = ticketDao.findAllByMovieNameAndPrice(movieName, price);
                   long time = (System.currentTimeMillis() + key.hashCode()) % CacheUtil.CACHE_TIME_MAX + 1;
                   if (time < CacheUtil.CACHE_TIME_MIN) {
                       time = CacheUtil.CACHE_TIME_MIN;
                   }
                   //放入缓存
                   redisTemplate.opsForValue()
                           .set(key, list, time, TimeUnit.SECONDS);
                   rLock.unlock();
               }else {
                   //没有拿到锁的线程
                   Thread.sleep(400);
               list=    this.findTicket(movieName,price);
               }
            }

            return list;
    }
}
